﻿#if LATER
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace LogoFX.Controls
{
    public class BreadCrumbItem:ContentControl
    {
        static BreadCrumbItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BreadCrumbItem), new FrameworkPropertyMetadata(typeof(BreadCrumbItem)));
        }

        #region IsSelected dependency property

        public bool IsSelected
        {
            get { return (bool) GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof (bool), typeof (BreadCrumbItem), new PropertyMetadata(default(bool), OnIsSelectedChanged));

        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BreadCrumbItem bci = (BreadCrumbItem) d;
            if((bool)e.NewValue)
            {
                bci.RaiseEvent(new RoutedEventArgs(BreadCrumb.SelectedEvent, bci));
            }
        }

        #endregion
    }

    [TemplatePart(Name="PART_PopupToggle",Type=typeof(ToggleButton))]
    [TemplatePart(Name = "PART_PopupList", Type = typeof(Selector))]
    public class BreadCrumb:HeaderedItemsControl
    {
        private BreadCrumbs _parentCrumbs;

        static BreadCrumb()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BreadCrumb), new FrameworkPropertyMetadata(typeof(BreadCrumb)));
        }

        public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent("Selected", 
                                                                                            RoutingStrategy.Bubble, 
                                                                                            typeof(RoutedEventHandler),
                                                                                            typeof(BreadCrumb));

        public static void AddSelectedHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.AddHandler(BreadCrumb.SelectedEvent, handler);
            }
        }

        public static void RemoveSelectedHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.RemoveHandler(BreadCrumb.SelectedEvent, handler);
            }
        }

       
        protected override void ClearContainerForItemOverride(DependencyObject element, object item)
        {
            BreadCrumbItem bci = (BreadCrumbItem)element;
            bci.Content = null;
            bci.ClearValue(ContentControl.ContentTemplateProperty);
            bci.ClearValue(ContentControl.ContentTemplateSelectorProperty);
            
            base.ClearContainerForItemOverride(element, item);
        }
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            BreadCrumbItem bci = (BreadCrumbItem)element;
            
            bci.SetBinding(ContentControl.ContentProperty,
                          new Binding("TtemTemplate") { Mode = BindingMode.OneWay, Source = this });
            bci.SetBinding(ContentControl.ContentTemplateProperty,
                          new Binding("TtemTemplate") { Mode = BindingMode.OneWay, Source = this });
            bci.SetBinding(ContentControl.ContentTemplateSelectorProperty,
                          new Binding("TtemTemplateSelector") { Mode = BindingMode.OneWay, Source = this });
            bci.Content = item;
            base.PrepareContainerForItemOverride(element, item);
        }
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new BreadCrumbItem();
        }
        public BreadCrumbs ParentCrumbs
        {
            get { return _parentCrumbs; }
            set { _parentCrumbs = value; }
        }

        #region IsSelected dependency property

        public bool IsSelected
        {
            get { return (bool) GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof (bool), typeof (BreadCrumb), new PropertyMetadata(default(bool), OnIsSelectedChanged));

        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BreadCrumb bc = (BreadCrumb) d;
            if ((bool)e.NewValue)
                bc.RaiseEvent(new RoutedEventArgs(SelectedEvent,bc));
           // bc.InvokeIsSelectedChanged();
        }

        #endregion

        //public event RoutedEventHandler Selected;

        //public void InvokeIsSelectedChanged()
        //{
        //    RoutedEventHandler handler = Selected;
        //    if (handler != null) handler(this, new RoutedEventArgs(SelectedEvent,this));
        //}
        
    }

    public class BreadCrumbs : ItemsControl
    {
        static BreadCrumbs()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BreadCrumbs), new FrameworkPropertyMetadata(typeof(BreadCrumbs)));
        }

        protected override void ClearContainerForItemOverride(DependencyObject element, object item)
        {
            BreadCrumb bc = (BreadCrumb)element;
            bc.ClearValue(BreadCrumb.HeaderTemplateProperty);
            bc.ClearValue(BreadCrumb.HeaderTemplateSelectorProperty);
            bc.ClearValue(BreadCrumb.ItemTemplateProperty);
            bc.ClearValue(BreadCrumb.ItemTemplateSelectorProperty);
            bc.ClearValue(BreadCrumb.ItemsSourceProperty);
            bc.ParentCrumbs = null;
            base.ClearContainerForItemOverride(element, item);
        }
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            BreadCrumb bc = (BreadCrumb) element;
            bc.ParentCrumbs = this;
#if false
            bc.HeaderTemplate = ItemTemplate;
            bc.HeaderTemplateSelector = ItemTemplateSelector;
            bc.ItemTemplate = SubItemTemplate;
            bc.ItemTemplateSelector = SubItemTemplateSelector;
#else
            bc.SetBinding(BreadCrumb.HeaderTemplateProperty,
                          new Binding("TtemTemplate") { Mode = BindingMode.OneWay, Source = this });
            bc.SetBinding(BreadCrumb.HeaderTemplateSelectorProperty,
                          new Binding("TtemTemplateSelector") { Mode = BindingMode.OneWay, Source = this });
            bc.SetBinding(BreadCrumb.ItemTemplateProperty,
                          new Binding("SubItemTemplate") { Mode = BindingMode.OneWay, Source = this });
            bc.SetBinding(BreadCrumb.ItemTemplateSelectorProperty,
                          new Binding("SubItemTemplateSelector") { Mode = BindingMode.OneWay, Source = this });
            if (ItemsPath != null)
            {
                bc.SetBinding(BreadCrumb.ItemsSourceProperty,
                              new Binding("Header." + ItemsPath) {Mode = BindingMode.OneWay, Source = bc});
            }
            else
            {

                bc.SetBinding(BreadCrumb.ItemsSourceProperty,
                              new Binding("Header") { Mode = BindingMode.OneWay, Source = bc });
            }
            bc.Header = item;
#endif
            base.PrepareContainerForItemOverride(element, item);
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new BreadCrumb();
        }

        #region SubItemTemplate dependency property

        public DataTemplate SubItemTemplate
        {
            get { return (DataTemplate) GetValue(SubItemTemplateProperty); }
            set { SetValue(SubItemTemplateProperty, value); }
        }

        public static readonly DependencyProperty SubItemTemplateProperty =
            DependencyProperty.Register("SubItemTemplate", typeof (DataTemplate), typeof (BreadCrumbs), new PropertyMetadata(default(DataTemplate), OnSubItemTemplateChanged));

        private static void OnSubItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            
        }

        #endregion
#if !SILVERLIGHT
        #region SubItemTemplateSelector dependency property

        public DataTemplateSelector SubItemTemplateSelector
        {
            get { return (DataTemplateSelector) GetValue(SubItemTemplateSelectorProperty); }
            set { SetValue(SubItemTemplateSelectorProperty, value); }
        }

        public static readonly DependencyProperty SubItemTemplateSelectorProperty =
            DependencyProperty.Register("SubItemTemplateSelector", typeof (DataTemplateSelector), typeof (BreadCrumbs), new PropertyMetadata(default(DataTemplateSelector), OnSubItemTemplateSelectorChanged));

        private static void OnSubItemTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BreadCrumbs bc = (BreadCrumbs) d;
        }

        #endregion
#endif

        #region ItemsPath dependency property

        public string ItemsPath
        {
            get { return (string) GetValue(ItemsPathProperty); }
            set { SetValue(ItemsPathProperty, value); }
        }

        public static readonly DependencyProperty ItemsPathProperty =
            DependencyProperty.Register("ItemsPath", typeof (string), typeof (BreadCrumbs), new PropertyMetadata(default(string), OnItemsPathChanged));

        private static void OnItemsPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            
        }

        #endregion

        #region ItemValuePath dependency property

        public string ItemValuePath
        {
            get { return (string) GetValue(ItemValuePathProperty); }
            set { SetValue(ItemValuePathProperty, value); }
        }

        public static readonly DependencyProperty ItemValuePathProperty =
            DependencyProperty.Register("ItemValuePath", typeof (string), typeof (BreadCrumbs), new PropertyMetadata(default(string), OnItemValuePathChanged));

        private static void OnItemValuePathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            
        }

        #endregion
    }

    [TemplatePart(Name = "PART_BreadCrumbs", Type = typeof(BreadCrumbs))]
    public class BreadCrumbsContainer:PopupHeaderedContentControl
    {
        private readonly List<object> _currentChildPath = new List<object>();
        private BreadCrumbs _breadCrumbs;

        static BreadCrumbsContainer()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BreadCrumbsContainer), new FrameworkPropertyMetadata(typeof(BreadCrumbsContainer)));
        }


        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _breadCrumbs = GetTemplateChild("PART_BreadCrumbs") as BreadCrumbs;
            if (_breadCrumbs != null)
            {
                _breadCrumbs.ItemsSource = CurrentChildPath;
                _breadCrumbs.SetBinding(BreadCrumbs.ItemsPathProperty, new Binding("ItemsPath") {Source = this});
            }

        }

        #region Root dependency property

        public object Root
        {
            get { return (object) GetValue(RootProperty); }
            set { SetValue(RootProperty, value); }
        }

        public static readonly DependencyProperty RootProperty =
            DependencyProperty.Register("Root", typeof (object), typeof (BreadCrumbsContainer), new PropertyMetadata(default(object), OnRootChanged));

        private static void OnRootChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BreadCrumbsContainer bcc = (BreadCrumbsContainer)d;
            bcc._currentChildPath.Clear();
            bcc._currentChildPath.AddRange(bcc.BuildPathBFS(bcc.Root, bcc.Root));
        }

        #endregion

        #region ItemsPath dependency property

        public string ItemsPath
        {
            get { return (string)GetValue(ItemsPathProperty); }
            set { SetValue(ItemsPathProperty, value); }
        }

        public static readonly DependencyProperty ItemsPathProperty =
            DependencyProperty.Register("ItemsPath", typeof(string), typeof(BreadCrumbsContainer), new PropertyMetadata(default(string), OnItemsPathChanged));

        private static void OnItemsPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        #endregion

        #region SelectedValue dependency property

        public object SelectedValue
        {
            get { return (object) GetValue(SelectedValueProperty); }
            set { SetValue(SelectedValueProperty, value); }
        }

        public List<object> CurrentChildPath
        {
            get { return _currentChildPath; }
        }

        public static readonly DependencyProperty SelectedValueProperty =
            DependencyProperty.Register("SelectedValue", typeof (object), typeof (BreadCrumbsContainer), new PropertyMetadata(default(object), OnSelectedValueChanged));

        private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BreadCrumbsContainer bcc = (BreadCrumbsContainer) d;
            bcc._currentChildPath.Clear();
            bcc._currentChildPath.AddRange(bcc.BuildPathBFS(bcc.Root,e.NewValue));
        }

        #endregion

        private IList<object> BuildPathBFS(object source, object destination)
        {
            if (source.Equals(destination))
            {
                return new List<object> { source };
            }

            Dictionary<object, object> parents = new Dictionary<object,object> { { source, null } };

            Queue<object> q = new Queue<object>();

            q.Enqueue(source);

            while (q.Count > 0)
            {
                object current = q.Dequeue();
                IEnumerable children = this.GetChildren(current);
                foreach (object child in children)
                {
                    if (child != null && !parents.ContainsKey(child))
                    {
                        parents.Add(child, current);
                        q.Enqueue(child);

                        if (child.Equals(destination))
                        {
                            return this.GetPath(parents, child);
                        }
                    }
                }
            }

            return null;
        }

        private IList<object> GetPath(Dictionary<object,object> h, object n)
        {
            IList<object> nodes = new List<object>();
            object tmp = n;
            do
            {
                nodes.Insert(0, tmp);
                tmp = h[tmp];
            }
            while (tmp != null);
            return nodes;
        }

        private IList<object> BuildPathDFS(object root, object node)
        {
            IList<object> result = null;
            if (root == null)
                return null;
            if (root.Equals(node))
            {
                result = new List<object>();
                result.Add(root);
                return result;
            }

            foreach (object treeNode in GetChildren(root))
            {
                result = BuildPathDFS(treeNode, node);
                if (result != null)
                {
                    result.Insert(0, root);
                    return result;
                }
            }

            return null;
        }

        private IEnumerable GetChildren(object node)
        {

            string[] tokens = ItemsPath.Split('.');

            if(tokens.Length == 0)
            {
                if (node is IEnumerable)
                    return (IEnumerable)node;
                else
                    return new object[] {};
            }

            object curPart = node;
            foreach (string token in tokens)
            {
                if (curPart == null)
                    return new object[] {};
                PropertyInfo childrenPropertyInfo = curPart.GetType().GetProperty(token);
                if (childrenPropertyInfo == null)
                    return new object[] {};
                curPart = childrenPropertyInfo.GetValue(curPart, new object[] {});                
            }
            
            if(curPart is IEnumerable)
                return (IEnumerable) curPart;

            return new object[] {};
        }
    }
}
Xaml Part

    <Style TargetType="local:BreadCrumbItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:BreadCrumbItem">
                    <Grid>
                        <ContentPresenter Content="{TemplateBinding Content}"
                                          ContentTemplate="{TemplateBinding ContentTemplate}"
                                          ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"></ContentPresenter>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="local:BreadCrumb">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical" IsItemsHost="True"></StackPanel>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:BreadCrumb">
                    <Grid>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition></ColumnDefinition>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <ContentPresenter Grid.Column="0" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}">
                            </ContentPresenter>
                            <local:PopupHeaderedContentControl Grid.Column="1">
                                <local:PopupHeaderedContentControl.Header>
                                    <Border Background="Red">
                                        <TextBlock Text="hhh"></TextBlock>
                                    </Border>
                                </local:PopupHeaderedContentControl.Header>
                                <local:PopupHeaderedContentControl.Content>
                                    <Border Background="White">
                                        <ItemsPresenter></ItemsPresenter>
                                    </Border>
                                </local:PopupHeaderedContentControl.Content>
                            </local:PopupHeaderedContentControl>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="local:BreadCrumbs">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" IsItemsHost="True"></StackPanel>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:BreadCrumbs">
                    <ItemsPresenter/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="local:BreadCrumbsContainer">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:BreadCrumbsContainer">
                    <Grid>
                    <local:BreadCrumbs x:Name="PART_BreadCrumbs" ItemsSource="{Binding CurrentChildPath}">

                    </local:BreadCrumbs>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
#endif
